package com.store.orm.mongo.curd.impl;

import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoDatabase;
import com.store.orm.mongo.curd.MongoUtil;
import com.store.orm.mongo.curd.Update;
import com.store.orm.util.JsonUtil;
import org.bson.Document;
import org.bson.conversions.Bson;

import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;

import static com.mongodb.client.model.Updates.combine;
import static com.mongodb.client.model.Updates.set;

/**
 * @author 宫静雨
 * @version 1.0
 */
public class MongoUpdate implements Update {
    private MongoDatabase database;
    private static final MongoUtil util = new MongoUtil();

    public MongoUpdate(MongoDatabase database) {
        this.database = database;
    }

    private <T> Bson helpT(T t) {
        try {
            LinkedHashMap<String, Object> map = util.parseTToMap(t);
            LinkedHashMap<String, Object> cascade = util.cascade(map);
            if (map.size() == 0) {
                throw new RuntimeException("The document may be empty.");
            }
            List<Bson> updateItems = new ArrayList<>();
            cascade.forEach((k, v) -> updateItems.add(set(k, v)));
            return combine(updateItems);
        } catch (Exception e) {
            throw new RuntimeException();
        }
    }

    @Override
    public <T> void update(Bson filter, T t) {
        MongoCollection<Document> collection = database.getCollection(util.collection(t.getClass()));
        collection.updateOne(filter, helpT(t));
    }

    @Override
    public <T> void updateMany(Bson filter, T ts) {
        MongoCollection<Document> collection = database.getCollection(util.collection(ts.getClass()));
        collection.updateMany(filter, helpT(ts));
    }

    private Bson helpJson(String json) {
        LinkedHashMap<String, Object> map = JsonUtil.parse(json);
        return getBson(map);
    }

    private Bson getBson(LinkedHashMap<String, Object> map) {
        if (map == null || map.size() == 0) {
            return null;
        }
        if (map.containsKey("id") || map.containsKey("_id")) {
            throw new RuntimeException();
        }
        LinkedHashMap<String, Object> cascade = util.cascade(map);
        List<Bson> updateItems = new ArrayList<>();
        cascade.forEach((k, v) -> updateItems.add(set(k, v)));
        return combine(updateItems);
    }

    @Override
    public void update(Bson filter, Class<?> cls, String json) {
        MongoCollection<Document> collection = database.getCollection(util.collection(cls));
        collection.updateOne(filter, helpJson(json));
    }

    @Override
    public void updateMany(Bson filter, Class<?> cls, String jsons) {
        MongoCollection<Document> collection = database.getCollection(util.collection(cls));
        collection.updateMany(filter, helpJson(jsons));
    }

    private Bson helpMap(LinkedHashMap<String, Object> map) {
        return getBson(map);
    }

    @Override
    public void update(Bson filter, Class<?> cls, LinkedHashMap<String, Object> map) {
        MongoCollection<Document> collection = database.getCollection(util.collection(cls));
        collection.updateOne(filter, helpMap(map));
    }

    @Override
    public void updateMany(Bson filter, Class<?> cls, LinkedHashMap<String, Object> map) {
        MongoCollection<Document> collection = database.getCollection(util.collection(cls));
        collection.updateMany(filter, helpMap(map));
    }

    @Override
    public void update(Bson filter, Class<?> cls, Bson content) {
        MongoCollection<Document> collection = database.getCollection(util.collection(cls));
        collection.updateOne(filter, content);
    }

    @Override
    public void updateMany(Bson filter, Class<?> cls, Bson content) {
        MongoCollection<Document> collection = database.getCollection(util.collection(cls));
        collection.updateMany(filter, content);
    }
}